import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PipedInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.InvalidPropertiesFormatException;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeMap;

import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileNameExtensionFilter;


public class LSCommDialog extends ConsoleDialog implements propertyReadWritable {

	/**
	 * 
	 */
	private static final String Title = " - LSComm ver1.4/HAKUSAN Corp.";  //  @jve:decl-index=0:
	private static final String propertyFile = new String("LScomm.properties");  //  @jve:decl-index=0:
	private static final long serialVersionUID = 1L;
	private transient JMenuItem jMenuItemTaCommand = null;//@
	private transient JMenuItem getJMenuItemSendSc = null;//@
	private transient JMenuItem jMenuItemIPSet = null; //@
	private transient JMenuItem jMenuItemHelp = null; //@
	private transient JMenuItem jMenuItemReceiveWin = null;//@
	private boolean receiveWinEnable = false;
	
//	private String DestIp = new String("127.0.0.1");
//	private int Port = 2700;
	private Properties config = new Properties();  //  @jve:decl-index=0:
	IPPortSettingDialog dialogIPSetting = new IPPortSettingDialog(null); //@
	protected DatagramSocket Ssocket = null; //@  //  @jve:decl-index=0:
	private LSCommDialog DialogMyself= null; //@
	
	public LSCommDialog(){
		//super();
		DialogMyself = null; //@
		initialize();
		frameTitle = Title;
		setTitle(frameTitle);
		URL imageIconUrl = getClass().getClassLoader().getResource("images/network32.png");
		ImageIcon icon = new ImageIcon(imageIconUrl);
		setIconImage(icon.getImage());
		
		File pf = new File(propertyFile);
		loadProp(pf);
		this.addWindowListener(new java.awt.event.WindowAdapter() {
			public void windowClosing(java.awt.event.WindowEvent e) {
				onExiting();
				System.exit(0);
			}
		});
		getJMenuOption().addSeparator();
		getJMenuOption().add(getJMenuItemIPSet());
		getJJMenuBarTop().add(getJMenuLS9xxx());
		getJJMenuBarTop().add(getJMenuLS88xx());
		getJMenuHelp().add(getJMenuItemHelp());
		getJMenuFile().add(	getJMenuItemLoad());
		getJMenuFile().add(	getJMenuItemSave());
		setVisible(true); 

	}
	
	private void initialize(){
		setSize(new Dimension(500, 200));
	}
	
	private void loadProp(File f){
		try {
			InputStream is = new FileInputStream(f);
			config.loadFromXML(is);
			is.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (InvalidPropertiesFormatException e){
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		super.readProperty(config);
		readProperty(config);
		
	}
	/**
	 * 
	 * @param f
	 */
	private void saveProp(File f){
		super.writeProperty(config);
		writeProperty(config);
		try {
			OutputStream os = new FileOutputStream(f);
			config.storeToXML(os, "This file is LSComm property file","Shift_JIS");
			os.flush();
			os.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	/**
	 * 
	 */
	private void onLoadCommand(){
		JFileChooser filechooser = new JFileChooser();//@
		filechooser.setFileSelectionMode( JFileChooser.FILES_ONLY);
		filechooser.setDialogTitle("Load ini file");
		FileNameExtensionFilter filter = new FileNameExtensionFilter("ini file", "ini");
		filechooser.addChoosableFileFilter(filter);
		int selected = filechooser.showOpenDialog(this);
		File file = null;
		if ( selected == JFileChooser.APPROVE_OPTION ) {
			file = filechooser.getSelectedFile ();
			loadProp(file);
		}
	}
	private void onSaveCommand(){
		JFileChooser filechooser = new JFileChooser();//@
		filechooser.setFileSelectionMode( JFileChooser.FILES_ONLY);
		filechooser.setDialogTitle("Save ini file");
		FileNameExtensionFilter filter = new FileNameExtensionFilter("ini file", "ini");
		filechooser.addChoosableFileFilter(filter);
		File tmp = new File("NoName.ini");
		filechooser.setSelectedFile(tmp);
		int selected = filechooser.showSaveDialog(this);
		File file = null;
		if ( selected == JFileChooser.APPROVE_OPTION ) {
			file = filechooser.getSelectedFile ();
			saveProp(file);
		}
	}
	private JMenu jMenuLS9xxx = null;//@
	protected JMenu getJMenuLS9xxx() {
		if (jMenuLS9xxx == null) {
			jMenuLS9xxx = new JMenu("LS9100"); //@
			jMenuLS9xxx.setMnemonic(KeyEvent.VK_9);
			jMenuLS9xxx.add(getJMenuItemSendTa());
			jMenuLS9xxx.add(getJMenuItemSendSc());
		}
		return jMenuLS9xxx;
	}
	private JMenu jMenuLS88xx = null;//@
	protected JMenu getJMenuLS88xx() {
		if (jMenuLS88xx == null) {
			jMenuLS88xx = new JMenu("LS8800"); //@
			jMenuLS88xx.setMnemonic(KeyEvent.VK_8);
			jMenuLS88xx.add(getJMenuItemReceiveWin());
		}
		return jMenuLS88xx;
	}


	
	private JMenuItem jMenuItemLoad = null;//@
	private	JMenuItem getJMenuItemLoad() {
		if (jMenuItemLoad == null) {
			jMenuItemLoad = new JMenuItem("Load ...");//@
			jMenuItemLoad.setIcon(new ImageIcon(getClass().getClassLoader().getResource("images/folder.png")));
			jMenuItemLoad.setMnemonic(KeyEvent.VK_L);
			jMenuItemLoad.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent arg0) {
					onLoadCommand();
				//getJTextAreaMain().setParamFromDialog();
				}
			});
		}
		return jMenuItemLoad;
	}
	
	private JMenuItem jMenuItemSave = null;//@
	private JMenuItem getJMenuItemSave() {
		if (jMenuItemSave == null) {
			jMenuItemSave = new JMenuItem("Save as...");//@
			jMenuItemSave.setIcon(new ImageIcon(getClass().getClassLoader().getResource("images/disk.png")));
			jMenuItemSave.setMnemonic(KeyEvent.VK_S);

			jMenuItemSave.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent arg0) {
					onSaveCommand();
					//getJTextAreaMain().setParamFromDialog();
				}
			});
		}
		return jMenuItemSave;
	}
	
	private HelpTextWindow HelpWindow =  null; //@
	private void onHelp(){
		if(HelpWindow==null){
			HelpWindow = new HelpTextWindow();  //@
		}
		HelpWindow.setSize(600, 800);//@
		HelpWindow.setAlwaysOnTop(true); //@
		HelpWindow.setVisible(true); //@ 
	}
	
	
	private void onExiting(){
		saveProp(new File(propertyFile));
		if(Ssocket!=null){
			Ssocket.disconnect();
			Ssocket.close();
			System.out.println("SocketClosed");
		}

	}
	public void readProperty(Properties prop) {
	    if(prop==null) return;
	    dialogIPSetting.settingPane.readProperty(prop);
		DestIp = dialogIPSetting.getJPanel().getIPString();
		Port   = dialogIPSetting.getJPanel().Port;
	}
	public void writeProperty(Properties prop) {
		if(prop==null) return;
	    dialogIPSetting.settingPane.writeProperty(prop);
	}
	

	private JMenuItem getJMenuItemHelp() {
		if (jMenuItemHelp == null) {
			jMenuItemHelp = new JMenuItem("HELP"); //@
			jMenuItemHelp.setIcon(new ImageIcon(getClass().getClassLoader().getResource("images/icon_info.gif")));
			jMenuItemHelp.setMnemonic(KeyEvent.VK_H);
			jMenuItemHelp.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent arg0) {
					onHelp(); //@
				}
			});
		}
		return jMenuItemHelp;
	}
	private JMenuItem getJMenuItemReceiveWin(){
		if (jMenuItemReceiveWin == null) {
			jMenuItemReceiveWin = new JMenuItem("Start Real-time Monitor"); //@
			jMenuItemReceiveWin.setIcon(new ImageIcon(getClass().getClassLoader().getResource("images/monitor.png")));
			 
			jMenuItemReceiveWin.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent arg0) {
					if(!receiveWinEnable){
						receiveWinEnable=true;
						jMenuItemReceiveWin.setText("Stop   Real-time Monitor");
						new Thread(new receiveWin()).start();
						setStatusBarEastMessage("RM");
					}
					else{
						jMenuItemReceiveWin.setText("Start Real-time Monitor");
						receiveWinEnable=false;
						setStatusBarEastMessage("");
					}
					
				}
			});
		}
		return jMenuItemReceiveWin;
	}
	private JMenuItem getJMenuItemSendTa() {
		if (jMenuItemTaCommand == null) {
			jMenuItemTaCommand = new JMenuItem("SEND TA 10"); //@
			jMenuItemTaCommand.setIcon(new ImageIcon(getClass().getClassLoader().getResource("images/monitor.png")));
 
			jMenuItemTaCommand.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent arg0) {
					new Thread(new Command_ta()).start();
					
				}
			});
		}
		return jMenuItemTaCommand;
	}
	private String DestIp = new String("127.0.0.1"); //@  //  @jve:decl-index=0:
	private int Port = 2700;
	private JMenuItem getJMenuItemIPSet() {
		if (jMenuItemIPSet == null) {
			jMenuItemIPSet = new JMenuItem("Destination IP");
			jMenuItemIPSet.setIcon(new ImageIcon(getClass().getClassLoader().getResource("images/server_connect.png")));

			jMenuItemIPSet.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent arg0) {
					dialogIPSetting.setLocationRelativeTo(DialogMyself);
					dialogIPSetting.setVisible(true);
					if(dialogIPSetting.OK){
						dialogIPSetting.getJPanel().UpdateData(false);
						DestIp = dialogIPSetting.getJPanel().getIPString();
						Port   = dialogIPSetting.getJPanel().Port;
					}
					
				}
			});
		}
		return jMenuItemIPSet;
	}
	private JMenuItem getJMenuItemSendSc() {
		if (getJMenuItemSendSc == null) {
			getJMenuItemSendSc = new JMenuItem("SEND SC");
			getJMenuItemSendSc.setIcon(new ImageIcon(getClass().getClassLoader().getResource("images/clock.png")));

			getJMenuItemSendSc.addActionListener(new ActionListener(){
				@Override
				public void actionPerformed(ActionEvent arg0) {
					Command_sc();
				}
			});
		}
		return getJMenuItemSendSc;
	}

	
	public static void main(String[] arg){
		new LSCommDialog(); //@
	}
	private boolean openUdp(){
		try {
			if(Ssocket == null){
				Ssocket = new DatagramSocket();
			}
		} catch (SocketException e) {
			JOptionPane.showMessageDialog(this,"Cannot bind port","Error",JOptionPane.OK_OPTION);
			return false;
		}
		return true;
	}
	private void waitms(int ms){
		long ct =System.currentTimeMillis();
		while((System.currentTimeMillis()-ct)<ms){
		}
	}
	private void sendCommand(String cmd){
		byte[] c = cmd.getBytes();
		getJTextAreaMain().outputChar(c);
		
	}
	private void Command_sc(){
		
		CmdList.add("q\n");
		CmdList.add("ct\n");
		
		TimeZone z = TimeZone.getDefault();
		Calendar cal2 = Calendar.getInstance(z);
		Calendar cal = null;
		while(true){
			cal = Calendar.getInstance(z);
			if(cal2 != cal) break;
		}
		String cmd = String.format("sc %d %d %d %d %d %d\n",
				cal.get(Calendar.YEAR),
				cal.get(Calendar.MONTH)+1,
				cal.get(Calendar.DATE),
				cal.get(Calendar.HOUR_OF_DAY),
				cal.get(Calendar.MINUTE),
				cal.get(Calendar.SECOND));
		CmdList.add(cmd);
		CmdList.add("q\n");
		new Thread(new Command_generic()).start();
		
	}
	
	ArrayList<String> CmdList = new ArrayList<String>();  //  @jve:decl-index=0:
	
	private class Command_generic implements Runnable {
		public Command_generic(){
		}
		public void run(){
			Iterator<String> ite = CmdList.iterator();
			while(ite.hasNext()){
				String cmd = ite.next();
				sendCommand(cmd);
				waitms(500);
			}
			CmdList.clear();
		}
	}
	///////////////////////////////////////////////////////////////////////////////////////////
	private class receiveWin implements Runnable {
		private wintime wtime = null;
		private int seq=0;
		private PipedInputStream input = null;
		private TreeMap<Integer,ArrayList<byte[]>> Data = new TreeMap<Integer,ArrayList<byte[]>>();
		
		public receiveWin(){
			openUdp();
			input = serialConsole.getPipedInputStream();
			serialConsole.OutBinaryMode=true;
			serialConsole.DisplayOff=true;
			wtold = null;
		}
		public void run(){
			int paclen=0;
			int count=0;
			byte [] pacdata = null;
			//pacdata = new byte[400];
			while(receiveWinEnable){
				try {
				int av;
				av = input.available();
				if(av<0) {
					break;
				}
				else if(av == 0){
					Thread.sleep(10);
					continue;
				}
				int dat = input.read();
				// System.out.print(String.format("%02x ",dat));
				switch(seq){
				case 0:
					if(dat==0x02){
						count++;
						if(count>=4){
							count=0;
							paclen=0;
							seq=1;
							//System.out.println("<HEADER");
						}
					}
					else{
						count=0;
						seq=0;
					}
					break;
				case 1:
					paclen = paclen*0x100 + (dat&0xff);
					//System.out.print("::" + paclen + "\n");
					count++;
					if(count>=4){
						if(paclen<4 || paclen>=0x10000){
							System.out.println("Error packet len " + paclen);
							count=0;
							seq=0;
						}
						else{
							count=0;
							pacdata = new byte[paclen];
							seq=2;
							//System.out.println("<LENGTH");
						}
					}
					break;
				case 2:
					pacdata[count++] = (byte)dat;
					if(count>=paclen){
						count=0;
						seq = 0;
						onReceive(pacdata);
						//System.out.println("<Data");
					}
					break;
				}
				} catch (IOException e) {
					e.printStackTrace();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			getJTextAreaMain().closeInputStream();
			serialConsole.OutBinaryMode=false;
			serialConsole.DisplayOff=false;
			waitms(50);
		}
		/**
		 * 
		 * @param pd
		 * @return
		 */
		private int getWinAdr(byte[] pd){
			return  unsigned_byte.convShort( pd[0])*0x100 +
			 unsigned_byte.convShort( pd[1]); // 2+1+1+1+6 + 1
		}
		private wintime getWinTime(byte[] pd){
			return  new wintime(pd,5);
		}
		private int getWinTimeMs(byte[] pd){
			int s = unsigned_byte.convShort(pd[11]);
			return ((s >> 4) & 0xf)*100 + (s & 0xf)*10;
		}
		/**
		 * 
		 * @param pacdata
		 */
		private wintime wtold=null;
		private void onReceive(byte[] pacdata){
			int  wadr  = getWinAdr(pacdata);
			wintime wt = getWinTime(pacdata);

			
			if(wtold == null){ // �ŏ�����
				wtold = new wintime(wt);
				return;
			}
			if(wt.getValueS() != wtold.getValueS()){// �b���ω�������
			//	System.out.println("Time: "+wtold.fmt()+" to "+wt.fmt());
				Set<Integer> ks = Data.keySet();
				Iterator<Integer> ite = ks.iterator();
				ArrayList<ArrayList<byte[]>> lst=new ArrayList<ArrayList<byte[]>>();
				while(ite.hasNext()){
					int ch = ite.next();
					ArrayList<byte[]> chd = Data.get(ch);
					if(chd.size() != 10){
						//System.out.println("RecvA5 too few millisec: " +chd.size() + " " +ch +"  " +wtold.fmt());
						break;
					}
					//System.out.println("RecvA5: "+ch +"  " +wtold.fmt());
					lst.add(chd);
					
				}
				conbineAndSend(lst);
				Data.clear();	
				wtold = new wintime(wt);
			}
			ArrayList<byte[]> d = Data.get(wadr);
			if(d==null) d = new ArrayList<byte[]>();
			d.add(pacdata);
			Data.put(wadr, d);
		}
		/**
		 * 
		 * @param chd
		 * @param ch
		 * @param wtold
		 */
		private void conbineAndSend(ArrayList<ArrayList<byte[]>> lst){
			TreeMap<Integer,int[]> senddat = new TreeMap<Integer,int[]>();
			wintime wtd = new wintime();
			for(int ch=0;ch<lst.size();ch++){
				// �ŏ��Ƀf�[�^���ׂ����`�F�b�N����
				boolean err=false;
				ArrayList<byte[]> chd = lst.get(ch);
				for(int i=0;i<chd.size();i++){
					byte[] d=chd.get(i);
					wtd = getWinTime(d);
					int wtms = getWinTimeMs(d);
					if(wtms != i*100){
						err=true;
						System.out.format("Error Time ms %d %d\n", wtms,i*100);
						break;	// ����millisec�����Ԃǂ��肩
					}
				}
				if(!err){
					ArrayList<int[]> idat=new ArrayList<int[]>();
					int idatsize = 0;
					// 1�b�����W�߂�
					for(int i=0;i<chd.size();i++){
						byte[] d=chd.get(i);
						wtd = getWinTime(d);
						//int wtms = getWinTimeMs(d);
						ChannelData cd = new ChannelData(d,12,wtd,5);
						idat.add(cd.getData()); // �f�R�[�h��̃f�[�^���W�߂�
						idatsize += cd.getData().length;
					}
					int[] secdata = new int[idatsize];
					int idx=0;
					for(int i=0;i<idat.size();i++){
						int[] da = idat.get(i);
						System.arraycopy(da, 0, secdata, idx, da.length);
						idx += da.length;
					}
					byte[] d=chd.get(0);
					int channel = getWinAdr(d);
					//System.out.format("Channel %d put %dbyte\n", channel,secdata.length);
					senddat.put(channel, secdata);
				}
			}
			txUDP(senddat,wtd);
		}
		int sequence = 0;
		int TxUdpCounter=0;
		private void txUDP(TreeMap<Integer,int[]> dat,wintime wtime){
			
			byte[] udpdat = winUtil.makeWinA0Frame(dat, wtime, sequence++);
			if(udpdat==null) return;
			InetSocketAddress adr;
			adr = new InetSocketAddress(DestIp, Port);
			DatagramPacket tosend;
			try {
				tosend = new DatagramPacket(udpdat, udpdat.length, adr);
				Ssocket.send(tosend);
				setStatusBarEastMessage(String.format("RM:UDPSnd=%,d",++TxUdpCounter));
				//System.out.println("Send "+udpdat.length + " byte");
			} catch (SocketException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		

		
		
		
		
	}
	
	
	
	///////////////////////////////////////////////////////////////////////////////////////////
	private class Command_ta implements Runnable {
		private wintime wtime = null;
		private int sequence=0;
		private PipedInputStream input = null;
		public Command_ta(){
			openUdp();
			Calendar cal = Calendar.getInstance(TimeZone.getDefault());
	        cal.setTime(new Date());
	        //int y = cal.get(Calendar.YEAR)+10;          // ��: 1997
	        int y = 2000;
	        //int m = cal.get(Calendar.MONTH) + 1;     // (0..11) + 1
	        int m = 1;
	        //int d = cal.get(Calendar.DATE);          // 1..31
	        int d = 1;
	        //int w = cal.get(Calendar.DAY_OF_WEEK);   // 1=Sun..7=Sat
	        int h = cal.get(Calendar.HOUR_OF_DAY);   // 0..23
	        int min = cal.get(Calendar.MINUTE);      // 0..59
	        int sec = cal.get(Calendar.SECOND);      // 0..59
	        wtime = new wintime(y,m,d,h,min,sec);
			input = serialConsole.getPipedInputStream();
		}
		public void run(){
			setStatusBarEastMessage("TA.");
			sendCommand("q\n");
			waitms(500);
			setStatusBarEastMessage("TA..");
			sendCommand("te\n");
			waitms(500);
			setStatusBarEastMessage("TA...");
			sendCommand("TA 10\n");
			long t1 = System.currentTimeMillis();
			byte[] buf = new byte[200];
			int index=0;
			int state=0;
			int linecount=0;
			String[] dline = new String[100];
			int timeout = 60000;
			while(System.currentTimeMillis()-t1 < timeout && state != -1){
				try {
					int av = input.available();
					if(av<0) {
						break;
					}
					else if(av == 0){
						Thread.sleep(10);
						continue;
					}
					int dat = input.read();
					t1 = System.currentTimeMillis();
					if((dat == '\n' || dat == '\r')){
						String d = new String(buf,0,index,"UTF-8");
						switch(state){
						case 0:
							if(d.contains("TA:")){
								state=1;
								timeout = 30000;
							}
							break;
						case 1:
							if(d.contains("L")){
								state = -1;
								break;
							}
							dline[linecount++] = d;
							if(linecount>=100){
								linecount=0;
								txUDP(dline);
							}
							timeout = 1000;
							break;
						case -1:
							break;
						}
						index=0;
					}
					else{
						buf[index++] = (byte)dat;	
						if(index>=200) index=0;
					}
				} catch (IOException e) {
					e.printStackTrace();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
			}
			getJTextAreaMain().closeInputStream();
			sendCommand("q\n");
			waitms(500);
			setStatusBarEastMessage("");


		}
		int TxUdpCounter=0;
		private void txUDP(String[] dline){
			String[] tok = dline[0].split(",");
			int chnum = tok.length;
			int sample = dline.length;
			TreeMap<Integer,int[]> dat = new TreeMap<Integer,int[]>();
			for(int i=0;i<chnum;i++){
				int[] bd = new int[sample];
				dat.put(i,bd);
			}
			for(int i=0;i<sample;i++){
				tok = dline[i].split(",");
				for(int j=0;j<chnum;j++){
					int b = Integer.valueOf(tok[j]);
					dat.get(j)[i] = b;
				}
			}
			
			byte[] udpdat = winUtil.makeWinA0Frame(dat, wtime, sequence++);
			wtime.inc_sec();
			InetSocketAddress adr;
			adr = new InetSocketAddress(DestIp, Port);
			DatagramPacket tosend;
			try {
				tosend = new DatagramPacket(udpdat, udpdat.length, adr);
				Ssocket.send(tosend);
				setStatusBarEastMessage(String.format("TA:UDPSnd=%,d",++TxUdpCounter));

				//System.out.println("Send ");
			} catch (SocketException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		

	}
}  //  @jve:decl-index=0:visual-constraint="10,10"
